#include "ShellMdiArea.h"
#include "MainWindow.h"
#include "DocumentWindow.h"

#include <QtWidgets>

#include <algorithm>

class DocumentHistory: public QListWidget
{
public: 
    DocumentHistory(QWidget * parent=nullptr) : QListWidget(parent) {}

    /// \todo Иногда при переходе фокуса на другой объект не закрывается окно при отпускании Ctrl.
    /// Попытка управлять через метод focusOutEvent не помогло. Желательно разобраться в проблеме
    // virtual void focusOutEvent(QFocusEvent * event) override
    // {
    //     QListWidget::focusOutEvent(event);

    //     if (event->lostFocus() && !isHidden())
    //         hide();
    // }
};


ShellMdiArea::ShellMdiArea(MainWindow * main)
    : QMdiArea(main)
    , _main(*main)
{
    Q_ASSERT(main);

    setViewMode(QMdiArea::TabbedView);
    setTabsClosable(true);
    setDocumentMode(true);
    // setTabPosition(QTabWidget::North);
    setTabPosition(QTabWidget::West);
    setActivationOrder(QMdiArea::ActivationHistoryOrder);
    // setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);

    _document_history = new DocumentHistory(/*this*/);
    _document_history->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
    // _document_history->setWindowFlags(Qt::FramelessWindowHint);
    _document_history->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    _document_history->hide();

    connect(this, &QMdiArea::subWindowActivated, this, &ShellMdiArea::subWindowActivated_slot);
    connect(_document_history, &QAbstractItemView::activated, this, &ShellMdiArea::activated_slot);
    // connect(_document_history, &QWidget::foc, this, &ShellMdiArea::activated_slot);

    installEventFilter(main);
}

DocumentWindow* ShellMdiArea::findDocumentWindow(const QString& file_name) const
{
    QString canonicalFilePath   = (file_name == "Setup")
                                ? file_name
                                : QFileInfo(file_name).canonicalFilePath();

    const QList<QMdiSubWindow *> subWindows = subWindowList();
    for (QMdiSubWindow *subwin : subWindows) {
        DocumentWindow *document_window = qobject_cast<DocumentWindow *>(subwin->widget());
        if (document_window && document_window->currentFile() == canonicalFilePath)
            return document_window;
    }
    return nullptr;
}

void ShellMdiArea::stepDocumentHistory(HistoryStepDirection direction, bool activate)
{
    if (_document_history->isHidden()) {
        _document_history->clear();

        for(const QString & file_path : _history) {
            DocumentWindow * document_window = findDocumentWindow(file_path);
            if (document_window) {
                QIcon icon = _main.filesystem_model().fileIcon(
                                _main.filesystem_model().index(document_window->currentFile()));

                if (icon.isNull())
                    icon = document_window->view_adaptor()->plugin()->icon();

                if (icon.isNull())
                    icon = windowIcon();

                QListWidgetItem * item = new QListWidgetItem(
                                                icon, 
                                                document_window->userFriendlyCurrentFile());
                item->setToolTip(document_window->currentFile());
                _document_history->insertItem(0,item);
            }
        }

        if (_document_history->count() > 0) {
            _document_history->setCurrentRow(0);

            const int max_visible_rows = 12;
            int visible_rows = qMin(_document_history->count(), max_visible_rows);
            int w = _document_history->sizeHintForColumn(0) 
                        + (_document_history->count() > max_visible_rows ? _document_history->verticalScrollBar()->sizeHint().width() : 0)
                        + 2 * _document_history->frameWidth();
            int h = _document_history->sizeHintForRow(0) * visible_rows 
                        + 2 * _document_history->frameWidth();
            _document_history->setFixedSize(w, h);

            QRect mg = _main.geometry();
            _document_history->move(mg.x() + mg.width()/2 - w/2, mg.y() + mg.height() / 2 - h/2);

            _document_history->show();

            _last_tooltip_font = QToolTip::font();
            QToolTip::setFont(_document_history->font());
        }
    }

    if (_document_history->count() > 0) {
        if (direction == HistoryStepDirection::Previous) {
            int row = _document_history->currentRow() + 1;
            if (row >= _document_history->count())
                row = 0;
            _document_history->setCurrentRow(row);                
        }
        else {
            int row = _document_history->currentRow() - 1;
            if (row < 0)
                row = _document_history->count() - 1;
            _document_history->setCurrentRow(row);                
        }

        if (activate)
            activated_slot(_document_history->currentIndex());
    }
}

void ShellMdiArea::keyReleaseEvent(QKeyEvent * key_event)
{
    if (!_document_history->isHidden()) {
        if (key_event->key() == Qt::Key_Escape) {
            _document_history->hide();
        }
        else if(key_event->key() == Qt::Key_Control) {
            activated_slot(_document_history->currentIndex());
        }
    }

    QMdiArea::keyReleaseEvent(key_event);
}

bool ShellMdiArea::eventFilter(QObject * object, QEvent * event)
{
    /// \note Для разных оконных менеджеров объявленные для QAction последовательности срабатывают
    /// по разному. Кроме того, независимо от заданной последовательности для переключения окон,
    /// в Qt всё равно работает встроенная поддержка Ctrl+Tab и Ctrl+Backtab.
    /// Здесь реализована попытка перехватить все варианты. Однако нужно проверять...
    /// Проверено для: Ubuntu 22.04, Manjaro KDE, Alt K
    
    if (event->type() == QEvent::KeyPress) {
        QKeyEvent * key_event = static_cast<QKeyEvent *>(event);

        if (key_event->modifiers().testFlag(Qt::ControlModifier)) {
            bool is_shortcut_and_keypress_duplicated 
                    = QKeySequence(QKeySequence::NextChild).matches(QKeySequence(Qt::CTRL + Qt::Key_Tab)) != QKeySequence::NoMatch;
            
            if (key_event->key() == Qt::Key_Tab) {
                if (!is_shortcut_and_keypress_duplicated)
                    stepDocumentHistory(HistoryStepDirection::Previous);
                return true;
            }
            else if (key_event->key() == Qt::Key_Backtab) {
                if (!is_shortcut_and_keypress_duplicated)
                    stepDocumentHistory(HistoryStepDirection::Oldest);
                return true;
            }
        }
    }
    else if (event->type() == QEvent::ShortcutOverride) {
        QKeyEvent * key_event = static_cast<QKeyEvent *>(event);

        if (key_event->matches(QKeySequence::NextChild)) {
            stepDocumentHistory(HistoryStepDirection::Previous);
            return true;
        }
        else if (key_event->matches(QKeySequence::PreviousChild)) {
            stepDocumentHistory(HistoryStepDirection::Oldest);
            return true;
        }
    }
    else if (event->type() == QEvent::Shortcut) {
        QShortcutEvent * shortcut_event = static_cast<QShortcutEvent *>(event);

        if (shortcut_event->key() == QKeySequence::NextChild) {
            // stepDocumentHistory(HistoryStepDirection::Previous);
            return true;
        }
        if (shortcut_event->key() == QKeySequence::PreviousChild) {
            // stepDocumentHistory(HistoryStepDirection::Oldest);
            return true;
        }
    }

    return QMdiArea::eventFilter(object, event);
}

void ShellMdiArea::subWindowActivated_slot(QMdiSubWindow *window)
{
    if (window) {
        DocumentWindow * document_window = qobject_cast<DocumentWindow *>(window->widget());
        if (document_window) {
            auto it = std::find(_history.begin(),_history.end(), document_window->currentFile());
            if (it != _history.end())
                _history.erase(it);
            _history.push_back(document_window->currentFile());
        }
    }
}

void ShellMdiArea::activated_slot(const QModelIndex &index)
{
    QListWidgetItem * item      = _document_history->item(index.row());
    QString           file_name = item->toolTip();

    _document_history->hide();
    QToolTip::setFont(_last_tooltip_font);

    _main.openFile(file_name);
}

